home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-02-16 | 65.3 KB | 2,935 lines |
- Newsgroups: comp.sources.misc
- organization: Xenix Support, FICC
- from: peter@ficc.uu.net (Peter da Silva)
- subject: v10i071: Improvements to Parseargs
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 10, Issue 71
- Submitted-by: peter@ficc.uu.net (Peter da Silva)
- Archive-name: parseargs
-
- You're missing some stuff I sent in. Some serious improvements to parseargs,
- for example.
-
- :
- #! /bin/sh
- # This is a shell archive, created at Ferranti International Controls Corp.
- # by peter (peter da silva, +1 713 274 5180) on Wed Feb 7 08:10:16 1990
- # Remove anything before the "#! /bin/sh" line, then unpack it by saving
- # it into a file and typing "sh file". If you do not have sh, you need
- # unshar, a dearchiving program which is widely available. In the absolute
- # wost case, you can crack the files out by hand.
- # If the archive is complete, you will see the message "End of archive."
- # at the end.
- # This archive contains the following files...
- # 'README'
- # 'README.PDS'
- # 'Makefile'
- # 'funclist.h'
- # 'parseargs.h'
- # 'useful.h'
- # 'ckalloc.c'
- # 'argtype.c'
- # 'fp_argtype.c'
- # 'funclist.c'
- # 'openpath.c'
- # 'amiga_args.c'
- # 'unix_args.c'
- # 'syserr.c'
- # 'traceset.c'
- # 'stest.c'
- # 'ckalloc.3'
- # 'funclist.3'
- # 'openpath.3'
- # 'parseargs.3'
- # 'syserr.3'
- # 'trace.3'
- # To extract them, run the following through /bin/sh
- echo x - README
- sed 's/^X//' > README << '//END_OF_FILE'
- X
- X NIFTY UTILITY LIBRARY
- X
- X Eric P. Allman
- X University of California
- X Berkeley, California
- X eric@Berkeley.EDU
- X
- X
- XSUMMARY
- X This directory contains a subset of a utility library that I have
- X used (in various forms) for several years now. This particular
- X version is rather sparse, being a relatively recent reimplementation.
- X
- X I am making this available as a result of the rather surprising
- X response to my C Advisor column in UNIX Review Vol. 7 No. 11 on
- X argument parsing, in which I described an alternative to getopt.
- X Several dozen people have asked for the source code -- an amazing
- X number, considering that in the four years prior to this column,
- X I have gotten perhaps six letters in toto.
- X
- X Rather than limiting this distribution to the single argument
- X parsing module, I have added several other routines, many of which
- X my more faithful readers will recognize.
- X
- XCOPY/REUSE POLICY
- X Permission is hereby granted to freely copy and redistribute this
- X software, provided that the author is clearly credited in all
- X copies and derivations. Neither the name of the author nor that
- X of the University may be used to endorse or promote products
- X derived from this software without specific written permission.
- X This software is provided ``As Is'' and without any express or
- X implied warranties.
- X
- XCONTENTS
- X This directory contains:
- X README -- this file.
- X Makefile -- a makefile for the library.
- X useful.h -- a general header file, used by most everything.
- X ckalloc.c -- an interface to malloc(3) which diagnoses
- X out of memory conditions. This topic was discussed
- X in the C Advisor column in UNIX Review Vol. 7 No 7.
- X ckalloc.3 -- documentation for ckalloc.
- X funclist.h -- a header file specific to the function list
- X routines in funclist.c.
- X funclist.c -- routines that provide lists of ``callout''
- X functions, used by several of the other routines
- X to handle errors.
- X funclist.3 -- documentation for the funclist routines.
- X lwp_dump.c -- a routine to dump the state of the LightWeight
- X Process system in SunOS 4.0 -- this isn't used, but
- X may be useful to some of you.
- X openpath.c -- a routine to open a file, searching through
- X a path of directories to find it.
- X openpath.3 -- documentation for openpath.
- X parseargs.h -- headers for the argument parser.
- X parseargs.c -- a command line argument parser. Popular
- X response to my C Advisor column about this routine
- X in UNIX Review Vol. 7 No. 11 prompted me to make
- X this distribution available.
- X parseargs.3 -- documentation for parseargs.
- X fp_args.c -- argument value parsers for floating point values;
- X used by parseargs. This is only included if you need
- X FP values. I had to break this out because RISC/os
- X 4.01 from Mips doesn't seem to support strtod in the
- X BSD environment. You may find you need to include
- X -lm for this to work.
- X syserr.c -- error message printing routines. A version of
- X this was discussed in the C Advisor column in UNIX
- X Review, Vol. 7 No. 7.
- X syserr.3 -- documentation for syserr.
- X traceset.c -- routines to set trace flags. The flags are
- X tested by macros contained in useful.h.
- X trace.3 -- documentation for the trace routines and macros.
- X stest.c -- a small test program for the argument parser.
- X
- X The parseargs routine really ought to have a way of matching a
- X list (e.g., return the rest of argv). This isn't especially
- X hard to do, but I haven't gotten around to it yet.
- X
- XDISCLAIMERS
- X I hacked this code up to (hopefully) work on ANSI C compilers,
- X since several readers seem to be interested in this sort of thing.
- X I can't claim to have really tested this.
- X
- X The original version was tested under SunOS 4.0 on SPARC architectures.
- X The version you see has been loosely tested on a Mips M/2000 running
- X RISC/os 4.01; I have only tried it in the BSD environment, and that
- X only loosely.
- X
- XACKNOWLEDGEMENTS
- X I wrote the first version of this code while working at the
- X International Computer Science Institute in Berkeley, CA.
- X
- X$Header: README,v 2.1 89/12/30 20:59:14 eric Exp $
- //END_OF_FILE
- echo x - README.PDS
- sed 's/^X//' > README.PDS << '//END_OF_FILE'
- XUpdate to parseargs by Peter da Silva (peter@ficc.uu.net).
- X(second update: more improvements to arg parsing, argChar type)
- X(third update, return to original calling sequence, argList type)
- X
- XParseargs is a really nifty set of routines, but it doesn't fit too
- Xwell with standard UNIX semantics. In particular, you can get into a
- Xlot of trouble using it in a script if it drops into interactive mode
- Xon you. Also, it's not as useful as it could be for non-UNIX systems.
- XTo make it work better, I've made a couple of changes.
- X
- XIt compiled straight out of the box on System III once I'd provided
- Xbcopy, bcmp, and strtol. The strtol I've provided is almost totally
- Xuntested, but hopefully you won't need to use it. It's only for folks with
- Xold UNIX systems.
- X
- XFirst change was to disable the interactive prompting for arguments.
- XI think that's inconsistent with usual UNIX semantics. You can undo
- Xthis change by #defining INTERACTIVE when compiling parseargs.c.
- X
- XThe second change was to allow for a trailing list of arguments. I
- Xoriginally implemented this by changing the calling sequence to parseargs.
- XOn reflection this would just produce incompatibilities, so I added a
- Xnew "type", argList. This handles a pointer to a list of names:
- X
- Xstruct namelist {
- X struct namelist *nl_next;
- X char *nl_name;
- X};
- X
- XThis is implemented with some "magic" in parseargs, and perhaps it would
- Xdo better as an additional flag, ARGLIST, and a set of listType routines
- Xto handle them. Also, it currently keeps the list in LIFO order. It would
- Xbe more convenient in FIFO order, though this would take a little more
- Xwork to implement (basically just stepping through the list in argList to
- Xfind the tail, instead of inserting at the head), and can be fixed in a
- Xsingle pass after parseargs returns with (say) !argv = reverselist(argv)!:
- X
- Xstruct namelist *reverselist(from)
- Xstruct namelist *from;
- X{
- X struct namelist *to, *tmp;
- X
- X to = NULL;
- X while(from) {
- X tmp = from->nl_next; /* remove top from old list */
- X from = from->nl_next;
- X tmp->nl_next = to; /* insert top in new list */
- X to = tmp;
- X }
- X return to;
- X}
- X
- XThe final change is the addition of a 'argChar' type. This parses character
- Xarguments (such as the '-T' option to 'awk'), accepting single characters,
- X'\nnn' octal escapes, and '^X' for control characters.
- X
- XParseargs itself no longer uses ckalloc, traceset, funclist, and so on.
- Xthese routines are pretty cool, but when you're grafting parseargs onto
- Xan existing program they just get in the way. Also, it's possible to make
- Xparseargs fail in a cleaner fashion by handling out-of-memory cases myself.
- XCertainly there's not going to be any loose memory lying around to be
- Xcollected when parseargs starts up! To turn on TRACE and the funclist code
- Xjust add -DTRACESTUFF and -DFUNCLISTSTUFF to the Makefile.
- X
- XAlso, the error messages have been made a bit more descriptive. Instead
- Xof saying "stest: value required for -c flag", it prints "stest: RepCount
- Xrequired for -c flag". The ad_prompt element should relly be a descriptive
- Xword that can be used in a sentence... or for non_UNIX systems a multi-
- Xcharacter or keyword based flag. I have an Amiga version included, for
- Xexample, that uses keyword syntax. In that version, the usage message reads:
- X
- XUsage: amiga_test <name> [GROUP <newsgroup>]... [REP <repcount>] +
- X [DIR <dirname>] [X] [Y] [Z] [TAB <tabchar>] [<file>]...
- X
- XInstead of:
- X
- XUsage: unix_test <Name> [-n <newsGROUP>]... [-c <REPcount>] \
- X [-d <DIRname>] [-x] [-y] [-z] [-t <TABchar>] [<File>]...
- X
- XThis would solve the old problem of UNIX programs sticking out like a
- Xsore thumb in other operating systems.
- X
- XThe Amiga version still needs to prompt for options if called with a
- Xsingle '?' as an argument. This may require some redesign: it's almost
- Xcertainly not going to be possible to stuff *extra* file names into
- Xargv. Perhaps something like:
- X
- X parseargs(&argc, &argv, "File");
- X
- X????????
- //END_OF_FILE
- echo x - Makefile
- sed 's/^X//' > Makefile << '//END_OF_FILE'
- X# $Header: Makefile,v 2.1 89/12/30 20:59:01 eric Exp $
- X
- XTARGET= /usr
- XLIBDIR= /lib
- XINCDIR= ${TARGET}/include
- X
- XINCLUDES= -I.
- XMODEL= -Ms
- XMODELNAME= S
- XSTYLE= unix
- XO= -O
- XOPTIONS= # -DINTERACTIVE -DTRACESTUFF -DFUNCLISTSTUFF
- X
- XCFLAGS= ${MODEL} ${INCLUDES} $O ${OPTIONS}
- X
- XOFILES= ckalloc.o \
- X argtype.o \
- X fp_argtype.o \
- X funclist.o \
- X openpath.o \
- X ${STYLE}_args.o \
- X syserr.o \
- X traceset.o \
- X strtol.o
- X
- XHFILES= funclist.h \
- X parseargs.h \
- X useful.h
- X
- XCFILES= ckalloc.c \
- X argtype.c \
- X fp_argtype.c \
- X funclist.c \
- X openpath.c \
- X amiga_args.c \
- X unix_args.c \
- X syserr.c \
- X traceset.c \
- X stest.c
- XMANFILES= ckalloc.3 \
- X funclist.3 \
- X openpath.3 \
- X parseargs.3 \
- X syserr.3 \
- X trace.3
- XXXFILES= README \
- X README.PDS \
- X Makefile
- X
- XOBJS= ${OFILES}
- XSRCFILES= ${XXFILES} ${HFILES} ${CFILES} ${MANFILES}
- XLIBARGS= ${MODELNAME}lib${STYLE}_args.a
- XLIBFILE= ${MODELNAME}libparse.a
- XLOCLIBS= ${LIBARGS}
- XSYSLIBS= -lm
- XLIBS= ${LOCLIBS} ${SYSLIBS}
- XSHAR= shar
- X
- X${STYLE}_test: stest.o ${LOCLIBS}
- X ${CC} ${CFLAGS} -o ${STYLE}_test stest.o ${LIBS}
- X
- Xckalloc.o funclist.o syserr.o: funclist.h
- X
- X${STYLE}_args.o: parseargs.h
- X
- X${LIBARGS}: ${OBJS}
- X ar rvu $@ ${OBJS}
- X ranlib $@
- X
- Xinstall: ${INCDIR}/parseargs.h ${LIBDIR}/${LIBFILE}
- X
- X${INCDIR}/parseargs.h: parseargs.h
- X (cd ${INCDIR}; rm -f ${HFILES})
- X cp ${HFILES} ${INCDIR}
- X
- X${LIBDIR}/${LIBFILE}: ${LIBARGS}
- X rm -f ${LIBDIR}/${LIBFILE}
- X cp ${LIBARGS} ${LIBDIR}/${LIBFILE}
- X ranlib ${LIBDIR}/${LIBFILE}
- X
- Xshar: parseargs.shar
- X
- Xparseargs.shar: ${SRCFILES}
- X rm -f parseargs.shar
- X ${SHAR} ${SRCFILES} > parseargs.shar
- X
- Xclean:
- X rm -f ${OFILES} ${LIBARGS} ${STYLE}_test tags stest.o
- X
- Xtags: ${CFILES} ${HFILES}
- X ctags ${CFILES} ${HFILES}
- //END_OF_FILE
- echo x - funclist.h
- sed 's/^X//' > funclist.h << '//END_OF_FILE'
- X/*
- X** FUNCLIST.H -- headers for function list routines
- X**
- X** $Header: funclist.h,v 2.0 89/12/24 00:56:23 eric Exp $
- X**
- X** Each entry in this list contains a pointer to a function to be
- X** invoked, and an integer argument to be passed to it.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- X#ifndef FUNCLIST
- X
- X#ifndef _USEFUL_H_
- X#include <useful.h>
- X#endif
- X
- X#define FUNCLIST struct _funclist
- X
- XFUNCLIST
- X{
- X FUNCLIST *_fl_next; /* next in chain */
- X VOID (*_fl_func)(); /* function to invoke */
- X ARBPTR _fl_arg; /* first argument */
- X};
- X
- X#define FUNCLISTNULL ((FUNCLIST *) NULL)
- X
- X#endif
- //END_OF_FILE
- echo x - parseargs.h
- sed 's/^X//' > parseargs.h << '//END_OF_FILE'
- X/*
- X** PARSEARGS.H -- declarations for argument vector parser
- X**
- X** $Header: parseargs.h,v 2.0 89/12/24 00:56:29 eric Exp $
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- X#ifndef ARGDESC
- X
- X#ifndef _USEFUL_H_
- X#include <useful.h>
- X#endif
- X
- X#define ARGDESC struct _argdesc
- X
- XARGDESC
- X{
- X char ad_name; /* flag name */
- X char ad_flags; /* flags */
- X BOOL (*ad_type) ARGS((ARGDESC *, char *, BOOL));
- X /* function to parse value */
- X ARBPTR ad_valp; /* pointer to value storage area */
- X char *ad_prompt; /* prompt string */
- X};
- X
- X/* bits for ad_flags */
- X#define ARGREQ 0x01 /* required argument */
- X#define ARGOPT 0x00 /* optional argument pseudo-flag */
- X#define ARGHIDDEN 0x02 /* don't display in usage message */
- X#define ARGGIVEN 0x08 /* (internal) argument has been specified */
- X
- X/* types available for ad_type */
- Xextern BOOL argBool ARGS((ARGDESC *, char *, BOOL));
- Xextern BOOL argChar ARGS((ARGDESC *, char *, BOOL));
- Xextern BOOL argStr ARGS((ARGDESC *, char *, BOOL));
- Xextern BOOL argInt ARGS((ARGDESC *, char *, BOOL));
- Xextern BOOL argShort ARGS((ARGDESC *, char *, BOOL));
- Xextern BOOL argLong ARGS((ARGDESC *, char *, BOOL));
- Xextern BOOL argFloat ARGS((ARGDESC *, char *, BOOL));
- Xextern BOOL argDouble ARGS((ARGDESC *, char *, BOOL));
- Xextern BOOL argList ARGS((ARGDESC *, char *, BOOL));
- X
- Xstruct namelist {
- X struct namelist *nl_next;
- X char *nl_name;
- X};
- X
- X#define ENDOFARGS { '\0' }
- X
- X#endif
- //END_OF_FILE
- echo x - useful.h
- sed 's/^X//' > useful.h << '//END_OF_FILE'
- X/*
- X** USEFUL.H -- various definitions of general interest
- X**
- X** $Header: useful.h,v 2.0 89/12/24 00:56:33 eric Exp $
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- X#ifndef _USEFUL_H_
- X#define _USEFUL_H_
- X
- X#include <stdio.h>
- X
- X/* give a stab at the multiple-language dilemma */
- X#ifdef __STDC__
- X#define ARGS(x) x
- X#define NOARGS (void)
- X#define __ANSI_C__
- X#else
- X#if defined(c_plusplus) || defined(__cplusplus)
- X#define ARGS(x) x
- X#define NOARGS ()
- X#define __ANSI_C__
- X#else
- X#define ARGS(x) ()
- X#define NOARGS ()
- X#endif
- X#endif
- X
- X#ifndef VOID
- X#ifdef __ANSI_C__
- X#define VOID void
- X#else
- X#define VOID int
- X#endif
- X#endif
- X
- X#ifndef TRUE
- X#define TRUE 1
- X#define FALSE 0
- X#endif
- X
- X#ifndef BOOL
- X#define BOOL char
- X#endif
- X
- X#ifndef STATIC
- X#ifndef NODEBUG
- X#define STATIC
- X#else
- X#define STATIC static
- X#endif
- X#endif
- X
- X#ifndef EXTERN
- X#define EXTERN extern
- X#endif
- X
- X#ifndef CONST
- X#ifdef __ANSI_C__
- X#define CONST const
- X#else
- X#define CONST
- X#endif
- X#endif
- X
- X#ifndef NULL
- X#define NULL 0
- X#endif
- X
- X#ifndef CHARNULL
- X#define CHARNULL ((char *) NULL)
- X#endif
- X
- X#define FILENULL ((FILE *) NULL)
- X
- X#ifdef __ANSI_C__
- X#define ARBPTR void *
- X#else
- X#define ARBPTR char *
- X#endif
- X#define __ (ARBPTR)
- X#define ARBNULL (__ NULL)
- X
- X#ifndef TRACESTUFF
- X#define NODEBUG
- X#endif
- X
- X#ifndef NODEBUG
- X#define _TRACE_SIZE 200
- Xextern unsigned char _TraceVect[_TRACE_SIZE];
- X#define TRACEF(f, l) (_TraceVect[f] >= l)
- X#define TRACE(f, l, m) (TRACEF(f, l) ? printf m : 0)
- X#else
- X#define TRACEF(f, l) (FALSE)
- X#define TRACE(f, l, m)
- X#endif
- X
- X#ifdef lint
- X#define VERSIONID(v)
- X#else
- X#define VERSIONID(v) static char _Version[] = v;
- X#endif
- X
- X#define BITSET(b, w) (((b) & (w)) != 0)
- X
- X#ifdef __STDC__
- X#include <string.h>
- X#else
- Xextern char *strchr ARGS((char *, char));
- Xextern char *strrchr ARGS((char *, char));
- X#endif
- X
- Xextern ARBPTR ckalloc ARGS((unsigned int));
- X
- X#define MAXINPUTLINE 200 /* maximum string input line */
- X#define MAXWORDLEN 100 /* maximum word (token) length */
- X
- X#ifndef BSD
- X#define bcopy(f,t,l) memcpy(t,f,l)
- X#define bcmp(s,t,l) memcmp(s,t,l)
- X#endif
- X
- X#endif /* _USEFUL_H_ */
- //END_OF_FILE
- echo x - ckalloc.c
- sed 's/^X//' > ckalloc.c << '//END_OF_FILE'
- X#include <useful.h>
- X#include <funclist.h>
- X
- XVERSIONID("$Header: ckalloc.c,v 2.0 89/12/24 00:56:21 eric Exp $");
- X
- X/*
- X** CKALLOC -- allocate memory, checking for error conditions
- X**
- X** If we cannot allocate memory, we call the list of functions
- X** in OutOfMemoryFuncs. We then try again. If the second attempt
- X** fails, we terminate the process.
- X**
- X** Parameters:
- X** size -- the number of bytes of memory to be allocated.
- X**
- X** Returns:
- X** A pointer to the allocated memory.
- X** Never returns if memory cannot be allocated.
- X**
- X** Side Effects:
- X** As implied by memory allocation.
- X**
- X** Globals:
- X** OutOfMemoryFuncs -- a FUNCLIST that is called when memory
- X** cannot be allocated.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- XFUNCLIST *OutOfMemoryFuncs = FUNCLISTNULL;
- X
- XARBPTR
- Xckalloc(size)
- X unsigned int size;
- X{
- X ARBPTR p;
- X extern char *malloc ARGS((unsigned int));
- X
- X p = __ malloc(size);
- X if (p == ARBNULL)
- X {
- X funclist_call(OutOfMemoryFuncs, ARBNULL);
- X p = __ malloc(size);
- X if (p == ARBNULL)
- X syserr("ckalloc: out of memory");
- X }
- X return (p);
- X}
- //END_OF_FILE
- echo x - argtype.c
- sed 's/^X//' > argtype.c << '//END_OF_FILE'
- X#include <useful.h>
- X#include <parseargs.h>
- X#include <ctype.h>
- X
- X#ifdef __STDC__
- Xtypedef void *pointer;
- X#else
- Xtypedef char *pointer;
- X#endif
- X
- Xextern pointer malloc();
- X
- X#define ALL_AD ad = argd; ad->ad_name != '\0'; ad++
- X#define ALL_DEFS ad = _DefaultArgs; ad->ad_name != '\0'; ad++
- X
- Xextern char *ProgName;
- X
- X/*
- X** ARGtype -- argument translation routines.
- X**
- X** Each of these converts a parameter value to the internal form,
- X** including validity checking. Their parameters and return values
- X** all behave identically.
- X**
- X** Parameters:
- X** ad -- the argument descriptor for this parameter.
- X** vp -- a pointer to the string input value.
- X** copyf -- if TRUE, the value will be destroyed later,
- X** and so should be copied if it will be retained
- X** (as for a string).
- X**
- X** Returns:
- X** TRUE -- if the conversion was successful. The actual
- X** value should be stored in the location indicated
- X** by ad->ad_valp.
- X** FALSE -- if the conversion failed. The reason for failure
- X** should be diagnosed using usrerr().
- X**
- X** Side Effects:
- X** The value should be stored through ad->ad_valp.
- X*/
- X
- XBOOL
- XargStr(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X char *cp;
- X
- X if (copyf)
- X {
- X register int i;
- X
- X i = strlen(vp) + 1;
- X cp = (char *) malloc(i);
- X if(!cp) {
- X usrerr("out of memory parsing %s", ad->ad_prompt);
- X return FALSE;
- X }
- X bcopy(vp, cp, i);
- X }
- X else
- X {
- X cp = vp;
- X }
- X *(char **) ad->ad_valp = cp;
- X return (TRUE);
- X}
- X
- XBOOL
- XargChar(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X auto char *vpp;
- X extern long strtol ARGS((char *, char **, int));
- X int status = FALSE;
- X char c;
- X
- X if (strlen(vp) == 2 && vp[0]=='^')
- X {
- X c = vp[1] ^ '@';
- X status = TRUE;
- X }
- X else if(strlen(vp) > 1 && vp[0]=='\\')
- X {
- X c = (int) strtol(&vp[1], &vpp, 8);
- X if (*vpp == '\0')
- X status = TRUE;
- X }
- X else if(strlen(vp) == 1)
- X {
- X c = *vp;
- X status = TRUE;
- X }
- X
- X if(status == TRUE)
- X *(char *) ad->ad_valp = c;
- X else
- X {
- X usrerr("invalid character argument '%s' for %s",
- X vp, ad->ad_prompt);
- X }
- X return status;
- X}
- X
- X/*ARGSUSED*/
- XBOOL
- XargInt(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X auto char *vpp;
- X extern long strtol ARGS((char *, char **, int));
- X
- X *(int *) ad->ad_valp = (int) strtol(vp, &vpp, 0);
- X if (*vpp != '\0')
- X {
- X usrerr("invalid integer argument '%s' for %s",
- X vp, ad->ad_prompt);
- X return (FALSE);
- X }
- X else
- X {
- X return (TRUE);
- X }
- X}
- X
- X/*ARGSUSED*/
- XBOOL
- XargShort(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X auto char *vpp;
- X extern long strtol ARGS((char *, char **, int));
- X
- X *(short *) ad->ad_valp = (short) strtol(vp, &vpp, 0);
- X if (*vpp != '\0')
- X {
- X usrerr("invalid integer argument '%s' for %s",
- X vp, ad->ad_prompt);
- X return (FALSE);
- X }
- X else
- X {
- X return (TRUE);
- X }
- X}
- X
- X/*ARGSUSED*/
- XBOOL
- XargLong(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X auto char *vpp;
- X extern long strtol ARGS((char *, char **, int));
- X
- X *(long *) ad->ad_valp = strtol(vp, &vpp, 0);
- X if (*vpp != '\0')
- X {
- X usrerr("invalid integer argument '%s' for %s",
- X vp, ad->ad_prompt);
- X return (FALSE);
- X }
- X else
- X {
- X return (TRUE);
- X }
- X}
- X
- Xstruct booltab
- X{
- X char *bname; /* string to match against */
- X char bneedmatch; /* number of characters that must match */
- X BOOL bval; /* value to use */
- X};
- X
- XSTATIC struct booltab _BoolTab[] =
- X{
- X "yes", 1, TRUE,
- X "no", 1, FALSE,
- X "true", 1, TRUE,
- X "false", 1, FALSE,
- X "on", 2, TRUE,
- X "off", 3, FALSE,
- X CHARNULL
- X};
- X
- X/*ARGSUSED*/
- XBOOL
- XargBool(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X register struct booltab *b;
- X register char *cp;
- X int l;
- X
- X /* convert input to lower case */
- X for (l = 0, cp = vp; *cp != '\0'; l++, cp++)
- X {
- X if (isupper(*cp))
- X *cp = tolower(*cp);
- X }
- X
- X /* search for a match in the table */
- X for (b = _BoolTab; b->bname != CHARNULL; b++)
- X {
- X /* if too short, don't even bother trying */
- X if (l < b->bneedmatch)
- X continue;
- X
- X if (bcmp(vp, b->bname, l) == 0)
- X {
- X /* got a match */
- X *(BOOL *) ad->ad_valp = b->bval;
- X return (TRUE);
- X }
- X }
- X
- X usrerr("invalid Boolean argument '%s' for %s", vp, ad->ad_prompt);
- X return (FALSE);
- X}
- X
- X#ifdef TRACESTUFF
- X/*ARGSUSED*/
- XBOOL
- XargTrace(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X traceset(vp);
- X return (TRUE);
- X}
- X#endif
- X
- X/*ARGSUSED*/
- XBOOL
- XargEnd(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X return (FALSE);
- X}
- X
- XBOOL
- XargList(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X char *cp;
- X struct namelist *nl;
- X
- X if (copyf)
- X {
- X register int i;
- X
- X i = strlen(vp) + 1;
- X cp = (char *) malloc(i);
- X if(!cp) {
- X usrerr("out of memory saving string %s", ad->ad_prompt);
- X return FALSE;
- X }
- X bcopy(vp, cp, i);
- X }
- X else
- X {
- X cp = vp;
- X }
- X
- X nl = (struct namelist *) malloc(sizeof *nl);
- X if(!nl) {
- X usrerr("out of memory saving arg %s", ad->ad_prompt);
- X if(copyf) free(cp);
- X return FALSE;
- X }
- X
- X nl->nl_next = *(struct namelist **) ad->ad_valp;
- X nl->nl_name = cp;
- X *(struct namelist **) ad->ad_valp = nl;
- X return (TRUE);
- X}
- //END_OF_FILE
- echo x - fp_argtype.c
- sed 's/^X//' > fp_argtype.c << '//END_OF_FILE'
- X#include <useful.h>
- X#include <parseargs.h>
- X
- XVERSIONID("$Header: fp_args.c,v 2.0 89/12/24 00:56:21 eric Exp $");
- X
- X/*
- X** PARSEARGV argument type functions for floating point operands.
- X**
- X** These are broken out to avoid loading the floating precision
- X** conversion routines when they aren't actually needed.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- X/*ARGSUSED*/
- XBOOL
- XargDouble(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X auto char *vpp;
- X extern double strtod ARGS((char *, char **));
- X
- X *(double *) ad->ad_valp = strtod(vp, &vpp);
- X if (*vpp != '\0')
- X {
- X usrerr("invalid floating point argument '%s' for %s",
- X vp, ad->ad_prompt);
- X return (FALSE);
- X }
- X else
- X {
- X return (TRUE);
- X }
- X}
- X
- X/*ARGSUSED*/
- XBOOL
- XargFloat(ad, vp, copyf)
- X register ARGDESC *ad;
- X register char *vp;
- X BOOL copyf;
- X{
- X auto char *vpp;
- X extern double strtod ARGS((char *, char **));
- X
- X *(float *) ad->ad_valp = (float) strtod(vp, &vpp);
- X if (*vpp != '\0')
- X {
- X usrerr("invalid floating point argument '%s' for %s",
- X vp, ad->ad_prompt);
- X return (FALSE);
- X }
- X else
- X {
- X return (TRUE);
- X }
- X}
- //END_OF_FILE
- echo x - funclist.c
- sed 's/^X//' > funclist.c << '//END_OF_FILE'
- X#include <useful.h>
- X#include <funclist.h>
- X
- XVERSIONID("$Header: funclist.c,v 2.0 89/12/24 00:56:22 eric Exp $");
- X
- X/*
- X** FUNCLIST_ADD -- add a function specification to a function list
- X**
- X** Parameters:
- X** flh -- the address of a pointer to a function list. Note
- X** that this must be a FUNCLIST **.
- X** func -- the function to add to the list.
- X** arg -- the first argument to the function.
- X**
- X** Returns:
- X** none.
- X**
- X** Side Effects:
- X** The indicated function is added to the function list
- X** for later invocation by funclist_call.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- XVOID
- Xfunclist_add(flh, func, arg)
- X FUNCLIST **flh;
- X VOID (*func)();
- X ARBPTR arg;
- X{
- X register FUNCLIST *fl;
- X
- X fl = (FUNCLIST *) ckalloc(sizeof *fl);
- X fl->_fl_func = func;
- X fl->_fl_arg = arg;
- X fl->_fl_next = *flh;
- X *flh = fl;
- X}
- X/*
- X** FUNCLIST_CALL -- call all the functions on a function list.
- X**
- X** Parameters:
- X** fl -- the function list to call. Unlike funclist_add,
- X** this should not be an indirect pointer.
- X** arg -- the second argument to the functions.
- X**
- X** Returns:
- X** none.
- X**
- X** Side Effects:
- X** As implied by the function list.
- X*/
- X
- XVOID
- Xfunclist_call(fl, arg)
- X register FUNCLIST *fl;
- X ARBPTR arg;
- X{
- X while (fl != FUNCLISTNULL)
- X {
- X (*fl->_fl_func)(fl->_fl_arg, arg);
- X fl = fl->_fl_next;
- X }
- X}
- //END_OF_FILE
- echo x - openpath.c
- sed 's/^X//' > openpath.c << '//END_OF_FILE'
- X#include <useful.h>
- X
- XVERSIONID("$Header: openpath.c,v 2.0 89/12/24 00:56:26 eric Exp $");
- X
- X/*
- X** OPENPATH -- open a file, searching through a path
- X**
- X** Parameters:
- X** fname -- the file name, relative to the desired path.
- X** mode -- the open mode, just like fopen.
- X** path -- the search path.
- X**
- X** Returns:
- X** FILENULL if the file could not be found at all.
- X** A FILE pointer open for reading for the first instance
- X** of the file that could be found in the path
- X** otherwise.
- X**
- X** Side Effects:
- X** none.
- X**
- X** Notes:
- X** Should really just find the file, not open it.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- Xchar *DefaultPath = CHARNULL;
- X
- X#ifndef DEFAULTROOTPATH
- X#define DEFAULTROOTPATH "/usr/local:/usr:~:"
- X#endif
- X
- XFILE *
- Xopenpath(fname, mode, path)
- X char *fname;
- X char *mode;
- X char *path;
- X{
- X register char *dp;
- X register char *ep;
- X register char *bp;
- X FILE *fp;
- X char fbuf[200];
- X extern char *getenv ARGS((char *));
- X
- X dp = path;
- X if (dp == CHARNULL)
- X {
- X dp = DefaultPath;
- X if (dp == CHARNULL)
- X {
- X /* locate the root of our utility tree */
- X dp = getenv("ROOTPATH");
- X if (dp == CHARNULL)
- X dp = DEFAULTROOTPATH;
- X DefaultPath = dp;
- X }
- X }
- X for (;; dp = ++ep)
- X {
- X register int l;
- X int i;
- X int fspace;
- X
- X /* extract a component */
- X ep = strchr(dp, ':');
- X if (ep == CHARNULL)
- X ep = &dp[strlen(dp)];
- X
- X /* find the length of that component */
- X l = ep - dp;
- X bp = fbuf;
- X fspace = sizeof fbuf - 2;
- X if (l > 0)
- X {
- X /*
- X ** If the length of the component is zero length,
- X ** start from the current directory. If the
- X ** component begins with "~", start from the
- X ** user's $HOME environment variable. Otherwise
- X ** take the path literally.
- X */
- X
- X if (*dp == '~' && (l == 1 || dp[1] == '/'))
- X {
- X char *home;
- X
- X home = getenv("HOME");
- X if (home != CHARNULL)
- X {
- X i = strlen(home);
- X if ((fspace -= i) < 0)
- X goto toolong;
- X bcopy(home, bp, i);
- X bp += i;
- X }
- X dp++;
- X l--;
- X }
- X if (l > 0)
- X {
- X if ((fspace -= l) < 0)
- X goto toolong;
- X bcopy(dp, bp, l);
- X bp += l;
- X }
- X
- X /* add a "/" between directory and filename */
- X if (ep[-1] != '/')
- X *bp++ = '/';
- X }
- X
- X /* now append the file name */
- X i = strlen(fname);
- X if ((fspace -= i) < 0)
- X {
- X toolong:
- X fprintf(stderr, "openpath: pathname too long (ignored)\n");
- X *bp = '\0';
- X fprintf(stderr, "\tDirectory \"%s\"\n", fbuf);
- X fprintf(stderr, "\tFile \"%s\"\n", fname);
- X continue;
- X }
- X bcopy(fname, bp, i + 1);
- X
- X /* try to open that file */
- X fp = fopen(fbuf, mode);
- X
- X /* if it exists, all is well */
- X if (fp != FILENULL)
- X return (fp);
- X
- X /* if not, and no other alternatives, life is bleak */
- X if (*ep == '\0')
- X return (FILENULL);
- X
- X /* otherwise try the next component in the search path */
- X }
- X}
- //END_OF_FILE
- echo x - amiga_args.c
- sed 's/^X//' > amiga_args.c << '//END_OF_FILE'
- X#include <useful.h>
- X#include <parseargs.h>
- X#include <ctype.h>
- X
- XVERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
- X
- X/*
- X** PARSEARGS -- parse an argument vector, given a description
- X**
- X** Parameters:
- X** argv -- the argument vector as passed to main().
- X** argd -- the argument descriptor array.
- X**
- X** Returns:
- X** Nothing
- X** Exits with return code 20 if error in args.
- X** Exits with return code 10 if system error.
- X**
- X** Side Effects:
- X** Converts and stores arguments into variables as
- X** described by argd.
- X**
- X** Globals:
- X** DefaultPath -- the pathname of a set of places to
- X** look for system files, set from the ROOTPATH
- X** environment variable, or a default.
- X** ProgName -- the name of this program, saved for error
- X** messages and the like.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- X#define ALL_AD ad = argd; ad->ad_name != '\0'; ad++
- X#define ALL_DEFS ad = _DefaultArgs; ad->ad_name != '\0'; ad++
- X
- Xchar *ProgName;
- X
- X#ifdef TRACESTUFF
- Xextern BOOL argTrace ARGS((ARGDESC *, char *, BOOL));
- X#endif
- Xextern BOOL argEnd ARGS((ARGDESC *, char *, BOOL));
- X
- X/* default arguments -- apply to all programs */
- XSTATIC ARGDESC _DefaultArgs[] =
- X{
- X /* name flags type valp prompt */
- X#ifdef TRACESTUFF
- X 'T', ARGOPT, argTrace, ARBNULL, "TRACE",
- X#endif
- X '-', ARGOPT, argEnd, ARBNULL, "ARGS",
- X ENDOFARGS
- X};
- X
- X/* override argument descriptor, if none given by user */
- XSTATIC ARGDESC _NullArgDesc[] =
- X{
- X ENDOFARGS
- X};
- X
- XVOID
- Xparseargs(argv, argd)
- X char **argv;
- X ARGDESC argd[];
- X{
- X register ARGDESC *ad, *list;
- X register char **av;
- X register char *p;
- X BOOL noflags;
- X BOOL error;
- X extern char *getenv ARGS((char *));
- X
- X av = argv++;
- X /* save the name of this program (for error messages) */
- X ProgName = *av;
- X
- X /* allow null argument descriptor */
- X if (argd == (ARGDESC *) NULL)
- X argd = _NullArgDesc;
- X
- X /* clear out any cruft in the argument descriptor */
- X for (ALL_AD)
- X {
- X ad->ad_flags &= ~ARGGIVEN;
- X }
- X for (ALL_DEFS)
- X {
- X ad->ad_flags &= ~ARGGIVEN;
- X }
- X
- X /* run through the argument vector */
- X noflags = FALSE;
- X error = FALSE;
- X ad = NULL; /* No argument requested */
- X list = NULL;
- X while (*++av != CHARNULL)
- X {
- X /* Previous keyword required a value */
- X if(ad)
- X {
- X /* try to convert the type */
- X if (!(*ad->ad_type)(ad, *av, FALSE))
- X error = TRUE;
- X else
- X ad->ad_flags |= ARGGIVEN;
- X ad = NULL;
- X continue;
- X }
- X
- X /* If looking for keywords, see if this is one */
- X if(!noflags) {
- X for(ALL_AD)
- X if(match(*av, ad->ad_prompt) == 0)
- X break;
- X if(ad->ad_name == '\0')
- X for(ALL_DEFS)
- X if(match(*av, ad->ad_prompt) == 0)
- X break;
- X }
- X if(ad->ad_name == '\0')
- X ad = NULL;
- X
- X /* If we have a keyword here */
- X if(!noflags && ad)
- X {
- X list = NULL;
- X p = strchr(*av, '=');
- X if(p) /* matched NAME=VALUE */
- X {
- X p++;
- X /* try to convert the type */
- X if (!(*ad->ad_type)(ad, p, FALSE))
- X error = TRUE;
- X else
- X ad->ad_flags |= ARGGIVEN;
- X ad = NULL;
- X }
- X else
- X {
- X if (ad->ad_type == argBool)
- X {
- X *(BOOL *) ad->ad_valp = TRUE;
- X ad->ad_flags |= ARGGIVEN;
- X ad = NULL;
- X }
- X else if (ad->ad_type == argEnd)
- X {
- X noflags = TRUE;
- X ad->ad_flags |= ARGGIVEN;
- X ad = NULL;
- X }
- X else if (ad->ad_type == argList)
- X {
- X list = ad;
- X ad = NULL;
- X }
- X }
- X }
- X else /* it's a positional argument */
- X {
- X if(list) {
- X if (!argList(list, *av, FALSE))
- X error = TRUE;
- X list->ad_flags |= ARGGIVEN;
- X continue;
- X }
- X else
- X {
- X for (ALL_AD)
- X {
- X if (ad->ad_name == ' ' &&
- X (ad->ad_type == argList ||
- X !BITSET(ARGGIVEN, ad->ad_flags))
- X )
- X break;
- X }
- X if (ad->ad_name == '\0')
- X {
- X usrerr("too any arguments");
- X error = TRUE;
- X ad = NULL;
- X }
- X else
- X {
- X /* try to convert */
- X if (!(*ad->ad_type)(ad, *av, FALSE))
- X error = TRUE;
- X else
- X ad->ad_flags |= ARGGIVEN;
- X ad = NULL;
- X }
- X }
- X }
- X }
- X
- X /* If last argument was a keyword and required an option
- X * then complain about it
- X */
- X if(ad) {
- X usrerr("missing argument for %s", ad->ad_prompt);
- X error = TRUE;
- X }
- X *argv = NULL;
- X
- X /* now rescan for missing required arguments */
- X for (ALL_AD)
- X {
- X if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
- X {
- X if (!BITSET(ARGGIVEN, ad->ad_flags))
- X {
- X /* still didn't get a value... sigh */
- X if (ad->ad_name == ' ')
- X {
- X usrerr("%s required",
- X ad->ad_prompt);
- X }
- X else
- X {
- X usrerr("%s required for -%c flag",
- X ad->ad_prompt, ad->ad_name);
- X }
- X error = TRUE;
- X }
- X }
- X }
- X
- X if (error)
- X {
- X usage(argd);
- X exit(20);
- X }
- X}
- X/*
- X** USAGE -- print a usage message
- X**
- X** Parameters:
- X** argd -- the description of expected arguments.
- X**
- X** Returns:
- X** none
- X**
- X** Side Effects:
- X** prints on stderr
- X**
- X** Globals:
- X** MaxOutputLine -- the length of the maximum output line
- X** allowed before wrapping. This should be fetched
- X** from the terminal driver on systems that support
- X** this sort of thing.
- X*/
- X
- Xint MaxOutputLine = 72;
- X
- XVOID
- Xusage(argd)
- X ARGDESC *argd;
- X{
- X register ARGDESC *ad;
- X int ll;
- X int pl;
- X
- X fprintf(stderr, "Usage: %s", ProgName);
- X ll = strlen(ProgName) + 7;
- X
- X for (ALL_AD)
- X {
- X char keyword[BUFSIZ];
- X char name[BUFSIZ];
- X int i, j;
- X
- X j = 0;
- X for(i = 0; ad->ad_prompt[i]; i++) {
- X if(isupper(ad->ad_prompt[i])) {
- X keyword[j++] = ad->ad_prompt[i];
- X name[i] = tolower(ad->ad_prompt[i]);
- X }
- X else
- X name[i] = ad->ad_prompt[i];
- X }
- X name[i] = 0;
- X if(j > 0)
- X keyword[j] = 0;
- X else
- X strcpy(keyword, ad->ad_prompt);
- X
- X /* don't display hidden arguments */
- X if (BITSET(ARGHIDDEN, ad->ad_flags))
- X continue;
- X
- X /* figure out how wide this parameter is (for printing) */
- X if (ad->ad_name != ' ')
- X {
- X pl = strlen(keyword);
- X if (ad->ad_type != argBool)
- X pl += strlen(name) + 3;/* _< > */
- X }
- X else
- X {
- X pl = strlen(name) + 2; /* < > */
- X }
- X if (!BITSET(ARGREQ, ad->ad_flags))
- X pl += 2; /* [ ] */
- X if (ad->ad_type == argList)
- X pl += 3; /* ... */
- X pl += 1; /* leading sp */
- X
- X /* see if this will fit */
- X if (ll + pl > MaxOutputLine)
- X {
- X /* no... start a new line */
- X fprintf(stderr, " +\n\t");
- X ll = 7;
- X }
- X else
- X {
- X /* yes... just throw in a space */
- X fprintf(stderr, " ");
- X }
- X ll += pl;
- X
- X /* show the argument */
- X if (!BITSET(ARGREQ, ad->ad_flags))
- X fprintf(stderr, "[");
- X if (ad->ad_name != ' ')
- X {
- X fprintf(stderr, "%s", keyword);
- X if (ad->ad_type != argBool)
- X fprintf(stderr, " ");
- X }
- X if (ad->ad_name == ' ' || ad->ad_type != argBool)
- X fprintf(stderr, "<%s>", name);
- X if (!BITSET(ARGREQ, ad->ad_flags))
- X fprintf(stderr, "]");
- X if (ad->ad_type == argList)
- X fprintf(stderr, "...");
- X }
- X fprintf(stderr, "\n");
- X}
- X
- X/* match(s1, s2)
- X**
- X** Compares two strings, returning >0, <0, or =0 if they match. First a
- X** check is done on letters capitalised in the second word, and if this
- X** fails then a complete match is done. Case is ignored in both matches.
- X** This lets you use case to indicate what part of a keyword is significant.
- X*/
- Xint match(candidate, target)
- Xchar *target, *candidate;
- X{
- X int i, j;
- X char c;
- X
- X i = j = 0;
- X
- X while(target[i] || candidate[i]) {
- X while(islower(target[i])) i++;
- X if(!target[i]) {
- X if(!candidate[j]) return 0;
- X return dictcmp(target, candidate);
- X }
- X c = islower(candidate[j])
- X ? toupper(candidate[j])
- X : candidate[j];
- X if(target[i] != c) return dictcmp(target, candidate);
- X i++;
- X j++;
- X }
- X return 0;
- X}
- X
- Xint dictcmp(s1, s2) /* "Dictionary" comparison of two strings */
- Xchar *s1, *s2;
- X{
- X char c1, c2;
- X
- X while(*s1 || *s2) {
- X c1 = *s1++;
- X c2 = *s2++;
- X if(!c1 || !c2) return c1 - c2;
- X if(isupper(c1)) c1 = tolower(c1);
- X if(isupper(c2)) c2 = tolower(c2);
- X if(c1 != c2) return c1 - c2;
- X }
- X return 0;
- X}
- //END_OF_FILE
- echo x - unix_args.c
- sed 's/^X//' > unix_args.c << '//END_OF_FILE'
- X#include <useful.h>
- X#include <parseargs.h>
- X#include <ctype.h>
- X
- XVERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
- X
- X/*
- X** PARSEARGS -- parse an argument vector, given a description
- X**
- X** Parameters:
- X** argv -- pointer to the argument vector as passed to main().
- X** argd -- the argument descriptor array.
- X**
- X** Returns:
- X** Nothing.
- X** Exits with return code 2 if error in args.
- X** Exits with return code 1 if system error.
- X**
- X** Side Effects:
- X** Converts and stores arguments into variables as
- X** described by argd.
- X**
- X** Globals:
- X** DefaultPath -- the pathname of a set of places to
- X** look for system files, set from the ROOTPATH
- X** environment variable, or a default.
- X** ProgName -- the name of this program, saved for error
- X** messages and the like.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- X#define ALL_AD ad = argd; ad->ad_name != '\0'; ad++
- X#define ALL_DEFS ad = _DefaultArgs; ad->ad_name != '\0'; ad++
- X
- Xchar *ProgName;
- X
- X#ifdef TRACESTUFF
- Xextern BOOL argTrace ARGS((ARGDESC *, char *, BOOL));
- X#endif
- Xextern BOOL argEnd ARGS((ARGDESC *, char *, BOOL));
- X
- X/* default arguments -- apply to all programs */
- XSTATIC ARGDESC _DefaultArgs[] =
- X{
- X /* name flags type valp prompt */
- X#ifdef TRACESTUFF
- X 'T', ARGOPT, argTrace, ARBNULL, "TRACE",
- X#endif
- X '-', ARGOPT, argEnd, ARBNULL, "ARGS",
- X ENDOFARGS
- X};
- X
- X/* override argument descriptor, if none given by user */
- XSTATIC ARGDESC _NullArgDesc[] =
- X{
- X ENDOFARGS
- X};
- X
- XVOID
- Xparseargs(argv, argd)
- X char **argv;
- X ARGDESC argd[];
- X{
- X register ARGDESC *ad, *list;
- X register char **av;
- X register char *p;
- X int argc;
- X BOOL noflags;
- X BOOL error;
- X#ifdef INTERACTIVE
- X BOOL shouldprompt;
- X#endif
- X extern char *getenv ARGS((char *));
- X#ifdef INTERACTIVE
- X extern int isatty ARGS((int));
- X#endif
- X
- X av = argv++;
- X argc = 1;
- X
- X /* save the name of this program (for error messages) */
- X ProgName = *av;
- X
- X#ifdef INTERACTIVE
- X /* test to see if we are interactive */
- X shouldprompt = (BOOL) isatty(0) && (BOOL) isatty(2);
- X#endif
- X
- X /* allow null argument descriptor */
- X if (argd == (ARGDESC *) NULL)
- X argd = _NullArgDesc;
- X
- X /* clear out any cruft in the argument descriptor */
- X for (ALL_AD)
- X {
- X ad->ad_flags &= ~ARGGIVEN;
- X }
- X for (ALL_DEFS)
- X {
- X ad->ad_flags &= ~ARGGIVEN;
- X }
- X
- X /* run through the argument vector */
- X noflags = FALSE;
- X error = FALSE;
- X list = NULL;
- X while ((p = *++av) != CHARNULL)
- X {
- X if (*p == '-' && !noflags)
- X {
- X /* flag argument */
- X if (*++p == '-' && p[1] == '\0')
- X {
- X /* -- indicates end of flags */
- X noflags = TRUE;
- X list = NULL;
- X continue;
- X }
- X while (*p != '\0')
- X {
- X /* find the flag in the list */
- X for (ALL_AD)
- X {
- X if (ad->ad_name == *p)
- X break;
- X }
- X if (ad->ad_name == '\0')
- X {
- X for (ALL_DEFS)
- X {
- X if (ad->ad_name == *p)
- X break;
- X }
- X if (ad->ad_name == '\0')
- X {
- X usrerr("flag -%c unknown", *p++);
- X error = TRUE;
- X continue;
- X }
- X }
- X
- X /* move p up to point to the (possible) value */
- X p++;
- X
- X /* booleans are special, having no value */
- X if (ad->ad_type == argBool)
- X {
- X *(BOOL *) ad->ad_valp = TRUE;
- X ad->ad_flags |= ARGGIVEN;
- X continue;
- X }
- X#ifdef TRACESTUFF
- X else if (ad->ad_type == argTrace)
- X {
- X traceset(p);
- X ad->ad_flags |= ARGGIVEN;
- X break;
- X }
- X#endif
- X
- X /* now get the real value */
- X if (*p == '\0')
- X {
- X p = *++av;
- X if (p == CHARNULL || *p == '-')
- X {
- X av--;
- X usrerr("%s required for -%c flag",
- X ad->ad_prompt, ad->ad_name);
- X error = TRUE;
- X break;
- X }
- X }
- X
- X /* try to convert the type */
- X if (!(*ad->ad_type)(ad, p, FALSE))
- X error = TRUE;
- X else
- X ad->ad_flags |= ARGGIVEN;
- X if(ad->ad_type == argList)
- X list = ad;
- X else
- X list = NULL;
- X break;
- X }
- X }
- X else
- X {
- X /* parsing a list of arguments */
- X if(list) {
- X if (!argList(list, p, FALSE))
- X error = TRUE;
- X continue;
- X }
- X /* positional argument */
- X for (ALL_AD)
- X {
- X if (ad->ad_name == ' ' &&
- X (ad->ad_type == argList ||
- X !BITSET(ARGGIVEN, ad->ad_flags))
- X )
- X break;
- X }
- X if (ad->ad_name == '\0')
- X {
- X usrerr("too any arguments");
- X error = 1;
- X continue;
- X }
- X
- X /* try to convert */
- X if (!(*ad->ad_type)(ad, p, FALSE))
- X error = TRUE;
- X else
- X ad->ad_flags |= ARGGIVEN;
- X }
- X }
- X
- X /* now rescan for missing required arguments */
- X for (ALL_AD)
- X {
- X if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
- X {
- X#ifdef INTERACTIVE
- X /* can we prompt? */
- X while (shouldprompt && !error)
- X {
- X char buf[MAXINPUTLINE];
- X
- X fprintf(stderr, "%s? ", ad->ad_prompt);
- X fflush(stderr);
- X if (fgets(buf, sizeof buf, stdin) == CHARNULL)
- X break;
- X p = strchr(buf, '\n');
- X if (p != CHARNULL)
- X *p = '\0';
- X if (buf[0] == '\0')
- X {
- X usrerr("value required");
- X continue;
- X }
- X if ((*ad->ad_type)(ad, buf, TRUE))
- X {
- X ad->ad_flags |= ARGGIVEN;
- X break;
- X }
- X }
- X#endif
- X
- X if (!BITSET(ARGGIVEN, ad->ad_flags))
- X {
- X /* still didn't get a value... sigh */
- X if (ad->ad_name == ' ')
- X {
- X usrerr("%s required",
- X ad->ad_prompt);
- X }
- X else
- X {
- X usrerr("%s required for -%c flag",
- X ad->ad_prompt, ad->ad_name);
- X }
- X error = TRUE;
- X }
- X }
- X }
- X
- X if (error)
- X {
- X usage(argd);
- X exit(2);
- X }
- X
- X return argc;
- X}
- X/*
- X** USAGE -- print a usage message
- X**
- X** Parameters:
- X** argd -- the description of expected arguments.
- X**
- X** Returns:
- X** none
- X**
- X** Side Effects:
- X** prints on stderr
- X**
- X** Globals:
- X** MaxOutputLine -- the length of the maximum output line
- X** allowed before wrapping. This should be fetched
- X** from the terminal driver on systems that support
- X** this sort of thing.
- X*/
- X
- Xint MaxOutputLine = 72;
- X
- XVOID
- Xusage(argd)
- X ARGDESC *argd;
- X{
- X register ARGDESC *ad;
- X int ll;
- X int pl;
- X
- X fprintf(stderr, "Usage: %s", ProgName);
- X ll = strlen(ProgName) + 7;
- X
- X for (ALL_AD)
- X {
- X /* don't display hidden arguments */
- X if (BITSET(ARGHIDDEN, ad->ad_flags))
- X continue;
- X
- X /* figure out how wide this parameter is (for printing) */
- X if (ad->ad_name != ' ')
- X {
- X pl = 2; /* -x */
- X if (ad->ad_type != argBool)
- X pl += strlen(ad->ad_prompt) + 3;/* _< > */
- X }
- X else
- X {
- X pl = strlen(ad->ad_prompt) + 2; /* < > */
- X }
- X if (!BITSET(ARGREQ, ad->ad_flags))
- X pl += 2; /* [ ] */
- X if (ad->ad_type == argList) /* ... */
- X pl += 3;
- X pl += 1; /* leading sp */
- X
- X /* see if this will fit */
- X if (ll + pl > MaxOutputLine)
- X {
- X /* no... start a new line */
- X fprintf(stderr, " \\\n\t");
- X ll = 7;
- X }
- X else
- X {
- X /* yes... just throw in a space */
- X fprintf(stderr, " ");
- X }
- X ll += pl;
- X
- X /* show the argument */
- X if (!BITSET(ARGREQ, ad->ad_flags))
- X fprintf(stderr, "[");
- X if (ad->ad_name != ' ')
- X {
- X fprintf(stderr, "-%c", ad->ad_name);
- X if (ad->ad_type != argBool)
- X fprintf(stderr, " ");
- X }
- X if (ad->ad_name == ' ' || ad->ad_type != argBool)
- X fprintf(stderr, "<%s>", ad->ad_prompt);
- X if (!BITSET(ARGREQ, ad->ad_flags))
- X fprintf(stderr, "]");
- X if (ad->ad_type == argList)
- X fprintf(stderr, "...");
- X }
- X fprintf(stderr, "\n");
- X}
- //END_OF_FILE
- echo x - syserr.c
- sed 's/^X//' > syserr.c << '//END_OF_FILE'
- X#include <useful.h>
- X#include <funclist.h>
- X
- XVERSIONID("$Header: syserr.c,v 2.0 89/12/24 00:56:31 eric Exp $");
- X
- X/*
- X** SYSERR -- indicate a system error
- X**
- X** Parameters:
- X** m -- the printf() message to print.
- X** a, b, c, d, e -- parameters to the message
- X**
- X** Returns:
- X** never
- X**
- X** Side Effects:
- X** Terminates the process if no acceptable recover takes place.
- X**
- X** Globals:
- X** SyserrFuncs -- a list of functions to call.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- X#ifdef FUNCLISTSTUFF
- XFUNCLIST *SyserrFuncs = FUNCLISTNULL;
- X#endif
- X
- XVOID
- Xsyserr(m, a, b, c, d, e)
- X char *m;
- X{
- X static BOOL exiting = FALSE;
- X
- X /* print the error message */
- X _error_message(m, a, b, c, d, e);
- X
- X /* if we recursively syserr during exit, drop out now! */
- X if (exiting)
- X _exit(1);
- X
- X#ifdef FUNCLISTSTUFF
- X /* call any possible cleanup functions */
- X funclist_call(SyserrFuncs, ARBNULL);
- X#endif
- X
- X /* try a clean exit */
- X exiting = TRUE;
- X exit(1);
- X /*NOTREACHED*/
- X}
- X/*
- X** USRERR -- print a user error
- X**
- X** Parameters:
- X** m -- the printf() message to print.
- X** a, b, c, d, e -- parameters to the message
- X**
- X** Returns:
- X** none.
- X**
- X** Side Effects:
- X** clears the global error number.
- X*/
- X
- X#ifdef FUNCLISTSTUFF
- XFUNCLIST *UsrerrFuncs = FUNCLISTNULL;
- X#endif
- X
- XVOID
- Xusrerr(m, a, b, c, d, e)
- X char *m;
- X{
- X extern int errno;
- X
- X /* print the error message */
- X _error_message(m, a, b, c, d, e);
- X
- X#ifdef FUNCLISTSTUFF
- X /* allow cleanup actions */
- X funclist_call(UsrerrFuncs, ARBNULL);
- X#endif
- X
- X /* give us a clean slate */
- X errno = 0;
- X}
- X/*
- X** _ERROR_MESSAGE -- generic message printing routine.
- X**
- X** Includes the program name with the message, as well as the
- X** various possible error codes.
- X**
- X** Parameters:
- X** m -- the printf() message to print.
- X** a, b, c, d, e -- parameters to the message
- X**
- X** Returns:
- X** none.
- X**
- X** Side Effects:
- X** none.
- X**
- X** Globals:
- X** ProgName -- the name of the program.
- X*/
- X
- XSTATIC VOID
- X_error_message(m, a, b, c, d, e)
- X char *m;
- X{
- X extern char *ProgName;
- X int saveerr;
- X extern int errno;
- X
- X saveerr = errno;
- X if (ProgName != CHARNULL)
- X fprintf(stderr, "%s: ", ProgName);
- X fprintf(stderr, m, a, b, c, d, e);
- X fprintf(stderr, "\n");
- X if (saveerr != 0)
- X {
- X errno = saveerr;
- X perror("System error");
- X }
- X}
- //END_OF_FILE
- echo x - traceset.c
- sed 's/^X//' > traceset.c << '//END_OF_FILE'
- X#ifdef NODEBUG
- X#undef NODEBUG
- X#endif
- X#define TRACESTUFF
- X#include <useful.h>
- X#include <ctype.h>
- X
- XVERSIONID("$Header: traceset.c,v 2.0 89/12/24 00:56:33 eric Exp $");
- X
- X/*
- X** TRACESET -- set trace flags
- X**
- X** Parameters:
- X** s -- the string describing the trace flags desired.
- X**
- X** Returns:
- X** none.
- X**
- X** Side Effects:
- X** Sets values in the trace vector.
- X**
- X** Globals:
- X** _TraceVect -- used by TRACE and TRACEF to determine the
- X** current trace flag settings.
- X**
- X** Syntax:
- X** The argument points to a set of comma separated trace
- X** flag settings. Each setting is a trace flag name, or
- X** a range of trace flags separated by a hyphen. The
- X** setting may be followed by a dot and a level. For
- X** example, "5,23-26.4" sets trace flag 5 to level 1 (the
- X** default), and flags 23 through 26 to level 4.
- X**
- X** Trace flags names may be numeric or symbolic. Symbolic
- X** names are looked up in the file "lib/traceflags", which
- X** is found somewhere in the search path. This file has a
- X** simple "name <white-space> value" syntax.
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- XSTATIC FILE *_TraceSymFile = FILENULL;
- XSTATIC BOOL _TraceSymCant = FALSE;
- Xunsigned char _TraceVect[_TRACE_SIZE];
- X
- XVOID
- Xtraceset(s)
- X char *s;
- X{
- X int lo;
- X int hi;
- X int lev;
- X
- X if (s == CHARNULL || *s == '\0')
- X s = "0-999";
- X
- X do
- X {
- X /* get the low limit of the range */
- X lo = _tracetok(&s, TRUE);
- X if (lo < 0)
- X lo = 0;
- X
- X /* get the high limit of the range */
- X if (*s == '-')
- X hi = _tracetok(&s, TRUE);
- X else
- X hi = lo;
- X if (hi >= _TRACE_SIZE)
- X hi = _TRACE_SIZE - 1;
- X
- X /* get the trace level */
- X if (*s == '.')
- X lev = _tracetok(&s, FALSE);
- X else
- X lev = 1;
- X if (lev < 0)
- X lev = 1;
- X
- X /* now do the actual setting */
- X while (lo <= hi)
- X _TraceVect[lo++] = lev;
- X } while (*s != '\0');
- X
- X if (_TraceSymFile != FILENULL)
- X {
- X fclose(_TraceSymFile);
- X _TraceSymFile = FILENULL;
- X }
- X}
- X/*
- X** _TRACETOK -- extract a token
- X**
- X** Parameters:
- X** sp -- an indirect pointer to the string form. It is
- X** updated to point to the token terminator.
- X** symok -- if TRUE, a symbolic representation can be
- X** used.
- X**
- X** Returns:
- X** The value of the token.
- X** -1 on error.
- X**
- X** Side Effects:
- X** none.
- X*/
- X
- XSTATIC int
- X_tracetok(sp, symok)
- X char **sp;
- X BOOL symok;
- X{
- X register char *s = *sp;
- X register char *tp;
- X char tbuf[MAXWORDLEN + 1];
- X char dbuf[MAXINPUTLINE];
- X
- X /* skip leading cruft */
- X while (*s != '\0' && !isalnum(*s))
- X s++;
- X
- X /* extract token */
- X for (tp = tbuf; isalnum(*s); *tp++ = *s++)
- X continue;
- X *tp = '\0';
- X
- X /* drop trailing cruft */
- X while (isspace(*s))
- X s++;
- X *sp = s;
- X
- X /* now decode token */
- X if (isdigit(tbuf[0]))
- X return (atoi(tbuf));
- X if (!symok)
- X return (-1);
- X
- X /* look up symbol */
- X if (!_TraceSymCant && _TraceSymFile == FILENULL)
- X {
- X extern FILE *openpath ARGS((char *, char *, char *));
- X
- X _TraceSymFile = openpath("lib/traceflags", "r", CHARNULL);
- X }
- X if (_TraceSymFile == FILENULL)
- X {
- X _TraceSymCant = TRUE;
- X return (-1);
- X }
- X rewind(_TraceSymFile);
- X
- X /* search through the trace file for a matching line */
- X while (fgets(dbuf, sizeof dbuf, _TraceSymFile) != CHARNULL)
- X {
- X register char *ep;
- X extern char *_tracematch ARGS((char *, char *));
- X
- X /* comment? */
- X if (dbuf[0] == '#' || dbuf[0] == '\n')
- X continue;
- X
- X /* does it match? */
- X ep = _tracematch(tbuf, dbuf);
- X if (ep != CHARNULL)
- X return (atoi(ep));
- X }
- X return (-1);
- X}
- X
- XSTATIC char *
- X_tracematch(tp, dp)
- X register char *tp;
- X register char *dp;
- X{
- X for ( ; *tp != '\0'; tp++, dp++)
- X {
- X /* if we have an exact match, continue trying */
- X if (*tp == *dp)
- X continue;
- X
- X /* well, let's try a caseless match */
- X if (isupper(*tp) && tolower(*tp) == *dp)
- X continue;
- X if (isupper(*dp) && tolower(*dp) == *tp)
- X continue;
- X
- X /* well foo... I guess it doesn't match */
- X return (CHARNULL);
- X }
- X
- X /* check the boundary conditions */
- X if (!isspace(*dp))
- X return (CHARNULL);
- X
- X /* drop the trailing white space and return the pointer */
- X while (isspace(*dp))
- X dp++;
- X return (dp);
- X}
- //END_OF_FILE
- echo x - stest.c
- sed 's/^X//' > stest.c << '//END_OF_FILE'
- X#include <useful.h>
- X#include <parseargs.h>
- X
- XVERSIONID("$Header: stest.c,v 2.0 89/12/24 00:56:29 eric Exp $");
- X
- X/*
- X** STEST -- a simple test program for the argument parser
- X**
- X** Author:
- X** Eric Allman
- X** University of California, Berkeley
- X*/
- X
- Xint RepCount;
- Xchar *Name;
- Xchar *DirName = ".";
- XBOOL XFlag = FALSE;
- XBOOL YFlag = FALSE;
- XBOOL ZFlag = FALSE;
- Xchar TabChar = ':';
- Xstruct namelist *Argv = NULL;
- Xstruct namelist *Groups = NULL;
- X
- XARGDESC Args[] =
- X{
- X ' ', ARGREQ, argStr, __ &Name, "Name",
- X 'n', ARGOPT, argList, __ &Groups, "newsGROUP",
- X 'c', ARGOPT, argInt, __ &RepCount, "REPcount",
- X 'd', ARGOPT, argStr, __ &DirName, "DIRname",
- X 'x', ARGOPT, argBool, __ &XFlag, "Xflag",
- X 'y', ARGOPT, argBool, __ &YFlag, "Yflag",
- X 'z', ARGOPT, argBool, __ &ZFlag, "Zflag",
- X 't', ARGOPT, argChar, __ &TabChar, "TABchar",
- X ' ', ARGOPT, argList, __ &Argv, "File",
- X ENDOFARGS
- X};
- X
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X parseargs(argv, Args);
- X
- X printf("Name = \"%s\", DirName = \"%s\", RepCount = %d,\n",
- X Name, DirName, RepCount);
- X printf("XFlag = %d, YFlag = %d, ZFlag = %d, TabChar=%03o;\n",
- X XFlag, YFlag, ZFlag, TabChar);
- X
- X if(Groups) {
- X printf("Newsgroups: ");
- X while(Groups) {
- X printf("%s", Groups->nl_name);
- X Groups = Groups->nl_next;
- X if(Groups)
- X putchar(' ');
- X else
- X putchar('\n');
- X }
- X }
- X
- X if(Argv) {
- X printf("Remaining args: ");
- X while(Argv) {
- X printf("%s", Argv->nl_name);
- X Argv = Argv->nl_next;
- X if(Argv)
- X putchar(' ');
- X else
- X putchar('\n');
- X }
- X }
- X exit(0);
- X}
- //END_OF_FILE
- echo x - ckalloc.3
- sed 's/^X//' > ckalloc.3 << '//END_OF_FILE'
- X.\" $Header: ckalloc.3,v 2.0 89/12/24 00:56:12 eric Exp $
- X.TH CKALLOC 3
- X.SH NAME
- Xckalloc \- allocate memory safely
- X.SH SYNOPSIS
- Xvoid *ckalloc(size)
- X.br
- Xunsigned int size;
- X.PP
- X#include <funclist.h>
- X.br
- Xextern FUNCLIST *OutOfMemoryFuncs;
- X.SH DESCRIPTION
- X.I ckalloc
- Xallocates memory from the heap in the same manner as
- X.IR malloc (3).
- XHowever, if sufficient memory is unavailable,
- Xrecovery is attempted by calling the list of functions
- Xindicated by the
- X.I OutOfMemoryFuncs
- Xglobal function list
- X(see
- X.IR funclist (3)
- Xfor details).
- XAfter these functions are called,
- Xthe allocation is retried.
- X.PP
- XIf the second attempt fails,
- X.I ckalloc
- Ximmediately terminates the process with a message
- Xusing
- X.IR syserr (3).
- X.SH SEE ALSO
- Xmalloc(3),
- Xfunclist(3),
- Xsyserr(3)
- X.SH AUTHOR
- XEric Allman, University of California, Berkeley
- //END_OF_FILE
- echo x - funclist.3
- sed 's/^X//' > funclist.3 << '//END_OF_FILE'
- X.\" $Header: funclist.3,v 2.0 89/12/24 00:56:22 eric Exp $
- X.TH FUNCLIST 3
- X.SH NAME
- Xfunclist_add, funclist_call \- manipulate lists of function pointers
- X.SH SYNOPSIS
- X#include <funclist.h>
- X.PP
- Xvoid funclist_add(flp, func, arg1)
- X.br
- XFUNCLIST **flp;
- X.br
- Xvoid (*func)(void *, void *);
- X.br
- Xvoid *arg1;
- X.PP
- Xvoid funclist_call(fl, arg2)
- X.br
- XFUNCLIST *fl;
- X.br
- Xvoid *arg2;
- X.SH DESCRIPTION
- XA
- X.I "function list"
- Xis a linked list of function pointers
- Xthat can be invoked at some future time.
- XThese are often used to handle exceptional conditions
- Xin generic library routines.
- XThe implementation is not particularly efficient;
- Xthese are intended primarily to allow flexible recovery
- Xfrom relatively rare error conditions.
- X.PP
- XFunction lists are declared using:
- X.PP
- X FUNCLIST *FuncListHead = FUNCLISTNULL;
- X.PP
- XFunctions are added to the list using:
- X.PP
- X funclist_add(&FuncListHead, &func, arg1)
- X.PP
- Xwhere ``func'' is the name of the function to be invoked.
- XThe
- X.I arg1
- Xargument is passed as the first parameter to the function when it is called,
- Xand is otherwise uninterpreted.
- X.PP
- XFunction lists are invoked using:
- X.PP
- X funclist_call(FuncListHead, arg2)
- X.PP
- XFunctions are invoked in the opposite order of their addition
- Xto the function list.
- XEach function is called as:
- X.PP
- X func(arg1, arg2);
- X.PP
- XThat is, the first argument is from the addition to the list,
- Xand the second is from the invocation.
- X.SH BUGS
- XThere should be some way to remove functions from the list.
- X.SH AUTHOR
- XEric Allman, University of California, Berkeley.
- //END_OF_FILE
- echo x - openpath.3
- sed 's/^X//' > openpath.3 << '//END_OF_FILE'
- X.\" $Header: openpath.3,v 2.0 89/12/24 00:56:24 eric Exp $
- X.TH OPENPATH 3
- X.SH NAME
- Xopenpath \- open a file, searching through a search path
- X.SH SYNOPSIS
- XFILE *openpath(fname, mode, path)
- X.br
- Xchar *fname;
- X.br
- Xchar *mode;
- X.br
- Xchar *path;
- X.PP
- Xextern char *DefaultPath;
- X.SH DESCRIPTION
- X.I openpath
- Xopens a file like
- X.IR fopen (3),
- Xexcept it uses a search path.
- XA FILE pointer is returned for the first file matching the name
- Xthat could be opened
- Xin the search path.
- XIf no file name matches,
- XFILENULL is returned.
- X.PP
- XThe
- X.I mode
- Xis passed directly to
- X.IR fopen (3).
- X.PP
- XThe
- X.I path
- Xis a colon-separated list of possible directories.
- XEach element of the path can begin with a tilde (``~'')
- Xto interpolate the
- X$HOME
- Xenvironment variable.
- XZero length entries indicate the current directory.
- XIf the path is not specified (CHARNULL),
- Xthe external variable
- X.I DefaultPath
- Xis used.
- XThis is set from the
- X$ROOTPATH
- Xenvironment variable.
- XIf this is not set, a system default is used,
- Xusually ``/usr/local:/usr:~:''.
- X.SH SEE ALSO
- Xfopen(3)
- X.SH AUTHOR
- XEric Allman, University of California, Berkeley
- //END_OF_FILE
- echo x - parseargs.3
- sed 's/^X//' > parseargs.3 << '//END_OF_FILE'
- X.\" $Header: parseargs.3,v 2.0 89/12/24 00:56:26 eric Exp $
- X.TH PARSEARGS 3
- X.SH NAME
- Xparseargs, usage \- parse command line argument vectors
- X.SH SYNOPSIS
- X#include <parseargs.h>
- X.PP
- Xvoid parseargs(argv, argd)
- X.br
- Xchar *argvp[];
- X.br
- XARGDESC argd[];
- X.PP
- Xvoid usage(argd)
- X.SH DESCRIPTION
- XGiven a vector of string-valued arguments
- Xsuch as that passed to
- X.I main
- Xand a vector describing the possible arguments,
- X.I parseargs
- Xmatches actual arguments to possible arguments,
- Xconverts values to the desired type,
- Xand diagnoses problems such as
- Xmissing arguments,
- Xextra arguments,
- Xand argument values that are syntactically incorrect.
- X.PP
- XWhen invoked interactively,
- Xunder the UNIX operating system and
- Xif parseargs has been compiled for interactive operation,
- X.I parseargs
- Xprompts the user for argument values that are
- Xrequired but are not given on the command line,
- Xand values that are supplied but syntactically incorrect.
- X.PP
- XBy default this option is not compiled in to avoid problems in
- Xshell scripts, where a program unexpectedly going into interactive
- Xmode might tun out to be a little disconcerting.
- X.PP
- XGiven a description of possible arguments,
- X.I usage
- Xprints a reasonably friendly version of this description.
- X.PP
- XThe argument description vector
- Xcontains one entry for each possible flag.
- XEach entry has five fields:
- X.IP name \w'prompt'u+2n
- XThe single character name of the associated flag.
- XFor example, to indicate that the program is expecting a ``\-x'' flag,
- Xthis field would contain \'x\'.
- XPositional arguments (those without a ``\-\fIx\fP'' prefix)
- Xare indicated by passing a ``space'' character.
- X.IP flags
- XFlags modifying the semantics of this entry,
- XThese should have one of
- XARGREQ
- Xto indicate a required argument or
- XARGOPT
- Xto indicate an optional argument.
- XARGHIDDEN
- Xcan be ``ored'' in to indicate a flag that should not be printed
- Xin usage messages \(em
- Xfor example, flags intended for internal debugging purposes.
- X.IP type
- XThe type of the argument.
- XThis is actually a pointer to a function, as described below.
- XStandard types include
- XargBool (Boolean flags),
- XargStr (string-valued arguments),
- XargList (a LIFO list of string-valued arguments),
- XargChar (char-valued arguments),
- XargInt (native integer arguments),
- XargShort (short integer arguments),
- XargLong (long integer arguments),
- XargFloat (short floating point arguments),
- Xand
- XargDouble (long floating point arguments).
- X.IP valp
- XA pointer to the variable that should receive the converted value.
- XSince this is typed as ``pointer to anything'',
- Xthis field should be preceded with a double underscore (``_\|_'')
- X(a macro defined in parseargs.h)
- Xto perform the appropriate type cast.
- X.IP prompt
- XThe string used when prompting interactively for argument values,
- Xand printed in usage messages.
- X.PP
- XThe list of arguments is terminated using ENDOFARGS.
- X.PP
- XFor example, consider the description:
- X.RS
- X.PP
- X.nf
- Xint RepCount = 2;
- XBOOL Verbose = FALSE;
- Xchar *InFile;
- Xchar *OutFile = CHARNULL;
- XBOOL XRated = FALSE;
- Xstruct namelist *Files = NULL;
- X
- XARGDESC Args[] =
- X{
- X 'c', ARGOPT, argInt, __ &RepCount, "REPcount",
- X 'v', ARGOPT, argBool, __ &Verbose, "Verbose",
- X ' ', ARGREQ, argStr, __ &InFile, "INPUTfile",
- X ' ', ARGOPT, argStr, __ &OutFile, "OUTPUTfile",
- X 'X', ARGHIDDEN, argBool, __ &XRated, "XratedMODE",
- X ' ', ARGOPT, argList, __ &Files, "File",
- X ENDOFARGS
- X};
- X.fi
- X.RE
- X.PP
- XThis describes a program accepting up to three flag arguments and
- Xone or two positional arguments, plus a list of additional file arguments.
- XOnly the first positional argument is required.
- XThe possible flags (in UNIX) are:
- X.TP
- X\fB\-c\fP \fIcount\fP
- XAn integer repetition count.
- XThis defaults to two.
- X.TP
- X\fB\-v\fP
- XA Boolean ``verbose'' flag.
- XIt defaults to FALSE.
- X.TP
- X\fB\-X\fP
- XA Boolean ``X Rated'' flag.
- XThis is not printed in the usage message.
- X.PP
- XThe two positional arguments are both strings, as is the final list.
- XIn AmigaDOS, the options would be
- X\fBREP\fP \fBcount\fP,
- X\fBV\fP, and
- X\fXMODE\fP.
- X.SH ARGUMENT TYPE FUNCTIONS
- XThe argument types recognized by
- X.I parseargs
- Xcan be extended by adding new type functions.
- XArgument type functions are declared as:
- X.RS
- X.PP
- X.nf
- XBOOL argXxx(argd, argp, copyf)
- X ARGDESC *argd;
- X char *argp;
- X BOOL copyf;
- X.fi
- X.RE
- X.PP
- XThe
- X.I argd
- Xargument points to the descriptor for the argument being converted.
- XIts main use is to find the location in which to store the converted value,
- Xlocated in argd\(->ad_valp.
- XThe string value to be converted is passed in
- X.IR argp .
- XThe
- X.I copyf
- Xflag is TRUE if the
- X.I argp
- Xstring value must be copied when saved.
- XMost non-string types are copied implicitly
- X(for example, integer arguments are stored in binary form,
- Xso the original string value need not be saved),
- Xso this argument can usually be ignored.
- XPut simply, this flag is
- XTRUE
- Xwhen
- X.I argp
- Xpoints to a temporary buffer area.
- X.PP
- XThe type function successfully converts the value,
- Xit should return
- XTRUE.
- XOtherwise,
- Xit should print a message using
- X.IR usrerr (3)
- Xand return FALSE. This message should be of the form
- X\fB"invalid xxxx option 'yyyy' for Zzzz"\fP, where xxxx is the type of the
- Xoption, yyyy is the string passed in vp, and zzzz is the name (taken from
- X\fBad->ad_prompt\fP).
- X.PP
- XFor example, a type function that took a filename
- Xand stored an open file pointer might be coded as:
- X.RS
- X.PP
- X.nf
- X/*ARGSUSED*/
- XBOOL
- XargReadFile(argd, argp, copyf)
- X register ARGDESC *argd;
- X register char *argp;
- X BOOL copyf;
- X{
- X register FILE *fp;
- X
- X fp = fopen(argp, "r");
- X if (fp == NULL)
- X {
- X usrerr("cannot open '%s' for reading as %s",
- X argp, argd->ad_prompt);
- X return (FALSE);
- X }
- X *(FILE *) argd->ad_valp = fp;
- X return (TRUE);
- X}
- X.fi
- X.RE
- X.SH SEE ALSO
- Xsyserr(3)
- X.br
- XThe ``C Advisor'' column in
- X.ul
- XUNIX Review
- XVol. 7 No. 11.
- X.SH AUTHOR
- XEric Allman, University of California, Berkeley
- X.SH MODIFICATIONS
- XModified to accept a vector of arguments, better error messages,
- Xand AmigaDOS version by Peter da Silva.
- //END_OF_FILE
- echo x - syserr.3
- sed 's/^X//' > syserr.3 << '//END_OF_FILE'
- X.\" $Header: syserr.3,v 2.0 89/12/24 00:56:30 eric Exp $
- X.TH SYSERR 3
- X.SH NAME
- Xsyserr, usrerr \- display error messages
- X.SH SYNOPSIS
- Xvoid syserr(msg, arg1, ...)
- X.br
- Xchar *msg;
- X.br
- Xvoid *arg1;
- X.PP
- Xvoid usrerr(msg, arg1, ...)
- X.PP
- X#include <funclist.h>
- X.br
- Xextern FUNCLIST *SyserrFuncs;
- X.br
- Xextern FUNCLIST *UsrerrFuncs;
- X.PP
- Xextern char *ProgName;
- X.SH DESCRIPTION
- XThese routines print error messages.
- XUnrecoverable errors should be sent using
- X.IR syserr ,
- Xwhich is guaranteed to never return.
- XRecoverable errors can be printed using
- X.IR usrerr .
- X.PP
- XBoth routines label the message with the contents of the
- X.I ProgName
- Xvariable, which is set by
- X.IR parseargs (3)
- Xto the name of the invoking program.
- XThe
- X.I msg
- Xand up to five arguments are passed to
- X.IR fprintf (3)
- Xto be printed.
- XThe message should
- X.I not
- Xcontain a trailing newline;
- Xthis is added internally.
- XThe contents of the
- X.I errno
- Xglobal variable is then appended to the message.
- X.PP
- XAfter printing the message,
- X.I syserr
- Xinvokes the
- X.I SyserrFuncs
- Xfunction list.
- XA member function can attempt to clean up and return to a top loop
- Xusing
- X.IR longjmp (3)
- Xor some similar mechanism.
- XIf the function list returns normally,
- Xthe process is terminated.
- X.PP
- XAfter
- X.I usrerr
- Xprints the message,
- Xit invokes the
- X.I UsrerrFuncs
- Xfunction list.
- XMember functions can use non-local jumps if a ``quick abort'' policy
- Xis desired.
- XIf this function list returns,
- X.I usrerr
- Xreturns to the caller.
- XThe global
- X.I errno
- Xvariable is reset to zero.
- X.SH BUGS
- XShould allow an arbitrary number of arguments.
- X.PP
- XMessages printed by
- X.I syserr
- Xshould probably also be logged using
- X.IR syslog (3)
- Xor the equivalent.
- X.PP
- XIt is possible to get recursive calls to
- X.I syserr
- Xif one of the
- X.I SyserrFuncs
- Xcalls
- X.IR syserr .
- XSimilar comments apply to
- X.IR usrerr .
- X.SH SEE ALSO
- Xsyslog(3),
- Xfunclist(3),
- Xlongjmp(3),
- Xexit(3)
- //END_OF_FILE
- echo x - trace.3
- sed 's/^X//' > trace.3 << '//END_OF_FILE'
- X.\" $Header: trace.3,v 2.0 89/12/24 00:56:31 eric Exp $
- X.TH TRACE 3
- X.SH NAME
- XTRACE, TRACEF, traceset \- trace package
- X.SH SYNOPSIS
- X#include <useful.h>
- X.PP
- XBOOL TRACEF(flag, level)
- X.br
- Xint flag;
- X.br
- Xint level;
- X.PP
- XTRACE(flag, level, (\fIprintf arguments\fP));
- X.PP
- Xvoid traceset(tracestring)
- X.br
- Xchar *tracestring;
- X.SH DESCRIPTION
- XThe
- X.I traceset
- Xroutine and the
- X.I TRACE
- Xand
- X.I TRACEF
- Xmacros implement a simple trace flag package.
- XA large number of trace flags
- X(200 default)
- Xcan each be set to a trace level
- Xvarying from zero
- X(no tracing for this flag)
- Xto 255
- X(full tracing).
- X.PP
- XThe
- X.I TRACEF
- Xmacro tests whether the specified flag is set to at least the indicated level.
- XFor example:
- X.PP
- X if (TRACEF(24, 3))
- X.PP
- Xtests flag 24; if it is set to 3 or higher,
- Xthe
- X.B if
- Xstatement succeeds.
- X.PP
- XThe
- X.I TRACE
- Xmacro incorporates a
- X.IR printf (3)
- Xstatement.
- XFor example, the code:
- X.PP
- X TRACE(24, 3, ("xyzzy = %d\n", xyzzy));
- X.PP
- XPrints the ``xyzzy'' variable
- Xwhen trace flag 24 is set to level 3 or higher.
- XThe extra set of parentheses is important.
- X.PP
- XFlags can be adjusted using the
- X.I traceset
- Xroutine.
- XThis parses the trace string, setting indicated flags as it goes.
- XThe string is a comma-separated list of trace settings.
- XEach setting has the syntax:
- X.PP
- X flag[\-flag][.level]
- X.PP
- XIf the level is omitted, one is assumed.
- XIf only one flag is indicated,
- Xit is set individually.
- XIf a range of flags is given,
- Xall flags inclusively between the two values are set.
- XFor example:
- X.PP
- X 20\-29.2
- X.PP
- Xsets the ten flags numbered between 20 and 29 to level 2.
- X.PP
- XFlag names can be symbolic.
- XSymbolic names are looked up in the file
- X``<searchpath>/lib/traceflags'',
- Xwhere
- X<searchpath>
- Xis the default search path used by
- X.IR openpath (3).
- XThis file is a series of lines, each containing a flag name,
- Xwhite space,
- Xand the flag value.
- XBlank lines
- Xand lines beginning with `#' are ignored.
- XCase is ignored in flag names.
- X.SH SEE ALSO
- Xopenpath(3),
- Xparseargs(3)
- X.SH AUTHOR
- XEric Allman, University of California, Berkeley
- //END_OF_FILE
- echo "End of archive."
- # end of archive.
- exit 0
- ---
- _--_|\ Peter da Silva. +1 713 274 5180. <peter@ficc.uu.net>.
- / \
- \_.--._/ Xenix Support -- it's not just a job, it's an adventure!
- v "Have you hugged your wolf today?" `-_-'
-